﻿using System;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.Common;
using System.Diagnostics;
using System.Collections.Generic;
using System.Collections.Specialized;

using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;

using Microsoft.Practices.EnterpriseLibrary.Data;

using Microsoft.Practices.EnterpriseLibrary.Logging;
using Microsoft.Practices.EnterpriseLibrary.Logging.ExtraInformation;
using Microsoft.Practices.EnterpriseLibrary.Logging.Filters;
using Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners;
using Microsoft.Practices.EnterpriseLibrary.Logging.Configuration;

using Paragon;

namespace Paragon.Logging.Listeners
{
    [ConfigurationElementType(typeof(CustomTraceListenerData))]
    public class DbTraceListener : CustomTraceListener
    {
        public DbTraceListener(NameValueCollection configuration)
        {
        }

        public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, object data)
        {
            if (data is LogEntry && this.Formatter != null)
            {
                InsertEntry(eventCache, source, eventType, id, data);
                //this.WriteLine(this.Formatter.Format(data as LogEntry));
            }
            else
            {
                this.WriteLine(data.ToString());
            }
        }

        private void InsertEntry(TraceEventCache eventCache, string source, TraceEventType eventType, int id, object data)
        {
            if (data is LogEntry)
            {
                LogEntry entry = (LogEntry)data;
                try
                {
                    Database database = DatabaseFactory.CreateDatabase("Analytics-Log4Net");


                    DbCommand command = database.GetStoredProcCommand("Logging.ent.spInsertLogEntry");

                    string category = string.Empty;

                    if (entry.Categories != null && entry.Categories.Count > 0)
                    {
                        category = entry.Categories.First<string>();
                    }

                    database.AddInParameter(command, "Category", DbType.String, category);
                    database.AddInParameter(command, "Severity", DbType.String, entry.Severity.ToString());

                    database.AddInParameter(command, "Priority", DbType.Int32, entry.Priority);
                    database.AddInParameter(command, "EventId", DbType.Int32, entry.EventId);

                    database.AddInParameter(command, "AppDomain", DbType.String, entry.AppDomainName);

                    database.AddInParameter(command, "ThreadId", DbType.String, entry.Win32ThreadId);
                    database.AddInParameter(command, "ThreadName", DbType.String, entry.ManagedThreadName);

                    database.AddInParameter(command, "ProcessId", DbType.String, entry.ProcessId);
                    database.AddInParameter(command, "ProcessName", DbType.String, entry.ProcessName);

                    database.AddInParameter(command, "Title", DbType.String, entry.Title);
                    database.AddInParameter(command, "Message", DbType.String, entry.Message);
                    database.AddInParameter(command, "Exception", DbType.String, GetException(entry));

                    database.AddInParameter(command, "Machine", DbType.String, entry.MachineName);
                    database.AddInParameter(command, "IpAddress", DbType.String, GetIpAddress(entry));
                    database.AddInParameter(command, "Url", DbType.String, GetUrl(entry));

                    database.AddInParameter(command, "Username", DbType.String, GetUsername(entry));
                    database.AddInParameter(command, "SessionId", DbType.String, GetSessionId(entry));

                    database.AddInParameter(command, "Properties", DbType.String, entry.ExtendedProperties.ToXml<string, object>());
                    
                    database.ExecuteNonQuery(command);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                    Microsoft.Practices.EnterpriseLibrary.Logging.Logger.Write(new LogEntry() { Severity = TraceEventType.Error, Title = "Logging Error", Message = "Logging error: \r\n" + ex.ToString() });
                }
            }
        }

        public override void Write(string message)
        {
            // Do nothing
        }

        public override void WriteLine(string message)
        {
            // Do Nothing
        }

        private string GetException(LogEntry entry)
        {
            return GetPropertySafely(Logger.EXCEPTION_KEY, entry);
        }

        private string GetIpAddress(LogEntry entry)
        {
            return GetPropertySafely(Logger.IP_ADDRESS_KEY, entry);
        }

        private string GetUrl(LogEntry entry)
        {
            return GetPropertySafely(Logger.URL_KEY, entry);
        }

        private string GetUsername(LogEntry entry)
        {
            return GetPropertySafely(Logger.USERNAME_KEY, entry);
        }

        private string GetSessionId(LogEntry entry)
        {
            return GetPropertySafely(Logger.SESSION_ID_KEY, entry);
        }

        private string GetPropertySafely(string key, LogEntry entry)
        {
            if (entry.ExtendedProperties.ContainsKey(key))
            {
                return entry.ExtendedProperties[key].ToString();
            }
            else
            {
                return string.Empty;
            }
        }
    }
}
